namespace GYLite
{
	export class GYKeyboard
	{
		public static createId:number=0;
		private static _instance:GYKeyboard;
		public static getInstance():GYKeyboard
		{
			return GYKeyboard._instance = GYKeyboard._instance || new GYKeyboard;
		}		
		private _keyListeners:IKeyBoardData[];
		private _keyDownDict:Dictionary;
		private _typing:boolean;		
		/**是否在输入框输入时仍然发出按键事件*/
		public keyEnabledWhenTyping:boolean;
		public constructor()
		{var s = this;
			s._keyDownDict = new Dictionary;
			s._keyListeners = [];
			// GYSprite.stage.addEventListener(KeyboardEvent.KEY_DOWN, s.kDown, GYSprite.stage);
			document.addEventListener("keydown", function(e):void{s.kDown(e)});
			// GYSprite.stage.addEventListener(KeyboardEvent.KEY_UP, s.kUp, GYSprite.stage);
			document.addEventListener("keyup", function(e):void{s.kUp(e)});
			document.addEventListener("visibilitychange", function () {				
				if (document.visibilityState == "hidden") {
					s._keyDownDict = new Dictionary;
				}
			});
			window.addEventListener('blur', () => {
				s._keyDownDict = new Dictionary;
			});
		}
		protected resort():void
		{
			let s= this;
			s._keyListeners.sort(s.sort);
		}
		protected sort(a:IKeyBoardData, b:IKeyBoardData):number
		{		
			if(a.priority == b.priority)return a.createId < b.createId?-1:1;
			return a.priority > b.priority?1:-1;
		}
		protected find(k:IKeyBoardObject):number
		{
			let len:number;
			let s = this;
			len = s._keyListeners.length;
			while(--len>-1)
			{
				if(s._keyListeners[len].keyObject == k)
					return len;
			}
			return -1;
		}
		/**添加键盘监听，重复添加会覆盖
		 * @param k 监听键盘的对象
		 * @param priority 优先级，数字越大优先级越高
		*/
		public addKeyListener(k:IKeyBoardObject,priority:number=0):void
		{var s = this;			
			var ind:number=s.find(k);
			if(ind > -1)
				s._keyListeners.splice(ind,1);
			s._keyListeners.push({keyObject:k,createId:++GYKeyboard.createId,priority:priority});
			s.resort();
		}
		/**移除键盘监听
		 * @param k 移除监听键盘的对象
		*/
		public removeKeyListener(k:IKeyBoardObject):void
		{var s = this;
			var ind:number=s.find(k);
			if(ind == -1)return;
			s._keyListeners.splice(ind,1);
			s.resort();
		}
		private kDown(e:KeyboardEvent):void
		{var s = this;						
			var keyCode:number = e.keyCode;
			let keyData:IKeyBoardData;
			s._keyDownDict.setValue(keyCode, CommonUtil.loopTime);
			if(s._keyListeners.length == 0)return;
			if(s._typing && !s.keyEnabledWhenTyping)return;
			var len:number;
			var k:IKeyBoardObject;
			len = s._keyListeners.length;
			while(--len>-1)
			{
				keyData = s._keyListeners[len];
				k = keyData.keyObject;
				if(k.disposed)
				{
					s._keyListeners.splice(len, 1);
					continue;
				}
				k.kDown(keyCode,e);				
				if(k.keyFocus())break;
			}
		}
		private kUp(e:KeyboardEvent):void
		{var s = this;					
			var keyCode:number = e.keyCode;
			s._keyDownDict.setValue(keyCode, 0);
			if(s._keyListeners.length == 0)return;
			if(s._typing && !s.keyEnabledWhenTyping)return;
			var len:number;
			var k:IKeyBoardObject;			
			len = s._keyListeners.length;
			while(--len>-1)
			{
				k = s._keyListeners[len].keyObject;
				if(k.disposed)
				{
					s._keyListeners.splice(len, 1);
					continue;
				}				
				k.kUp(keyCode,e);
				if(k.keyFocus())break;
			}
		}
		/**按下键的时间戳，0为未按下*/
		public isKeyDown(keyCode:number):number
		{var s = this;
			return s._keyDownDict.getValue(keyCode);
		}
		public releaseKey(keyCode:number):void
		{var s = this;
			if(keyCode == -1)
			{
				s._keyDownDict = new Dictionary;
				return;
			}
			s._keyDownDict.setValue(keyCode, 0);
		}
		
		public isCtrlDown():boolean
		{var s = this;
			return s._keyDownDict.getValue(Keyboard.CONTROL) > 0;	
		}
		public isAltDown():boolean
		{var s = this;
			return s._keyDownDict.getValue(Keyboard.ALTERNATE) > 0;
		}
		public isShiftDown():boolean
		{var s = this;
			return s._keyDownDict.getValue(Keyboard.SHIFT) > 0;
		}
		public isTyping(val:boolean):void
		{
			this._typing = val;
		}
		public isCapsLock():boolean
		{
			return this._keyDownDict.getValue(Keyboard.CAPS_LOCK) > 0;
		}

	}
	export interface IKeyBoardData
	{
		/**监听按键的对象*/keyObject:IKeyBoardObject;
		/**优先级，数字越大优先级越高*/priority:number;
		/**创建的id，id越小创建时间越早*/createId:number;
	}
}